package wator.view.swing;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Observable;
import java.util.Observer;

import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import wator.model.Population;
import wator.model.Simulation;
import wator.model.SimulationThread;
import wator.view.UI;
import wator.view.swing.enums.AnimationSpeed;
import wator.view.swing.jogl.Jogl;

import com.jogamp.opengl.util.Animator;

/**
 * This is the swing implementation of the user interface. To use this
 * graphical user interface, initialize <code>singleton</code> in
 * {@link wator.view.UI} accordingly.
 * 
 * @author Barbara Sepic----------------------------------------------------------------------------------------
 */
public class SwingUI extends UI implements KeyListener, Observer {
	private static String FRAME_TITLE = "Wator Strategies Visualisation";
	private JFrame mainFrame;
	public static final int MAX_GRID_SIZE = 1000; 
	private boolean gridShown;
	private AnimationSpeed animationSpeed;
	private Grid grid;
	private Dimension canvasSize;
	private Jogl joglInstance;
	private JPanel container;
	private int time;
	private JPanel joglPane;
	private Population pop;
	private MenuPane menuPane;
	
	
	
	/* (non-Javadoc)
	 * @see wator.view.UI#initialize()
	 */
		
	@Override
	public void initialize() {
		time = 0;
		KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
        manager.addKeyEventDispatcher(new MyDispatcher());

		animationSpeed = AnimationSpeed.STOP;
		grid = new Grid();
		Rectangle window = GraphicsEnvironment.getLocalGraphicsEnvironment().
        		getMaximumWindowBounds();
		window.height -= 30;

		// ...............................................initialize Main frame
		mainFrame = new JFrame();
		mainFrame.setTitle(FRAME_TITLE);
        mainFrame.pack();
        mainFrame.setBounds(window);
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.setResizable(false);
        //mainFrame.addKeyListener(this);
          
        Dimension windowD = mainFrame.getSize();
        
        Container containerC = mainFrame.getContentPane();
        container = new JPanel();
        setSize(container, windowD);
        container.setLayout(new GridBagLayout());
        
        JScrollPane mainScroll = new JScrollPane();
        mainScroll.setViewportView(container);
        containerC.add(container);
        
        // ...............................................initialize menu panel 
        Dimension menuD = new Dimension(windowD.width/4, windowD.height);
        menuPane = new MenuPane(this, menuD);
        setSize(menuPane, menuD);
        GridBagConstraints gbc = new GridBagConstraints();
		gbc.gridx = 0;
		gbc.gridwidth = 1;
		gbc.gridy = 0;
		gbc.gridheight = 8;
		gbc.fill = GridBagConstraints.BOTH;
		container.add(menuPane, gbc);
        
		// ...............................................initialize jogl panel
		int w = windowD.width-menuD.width-10;
		int h = windowD.height - windowD.height/8 - 50;
		canvasSize = new Dimension(w, h);
		/*
		GLProfile glp = GLProfile.getDefault();
        GLCapabilities caps = new GLCapabilities(glp);
        GLCanvas canvas = new GLCanvas(caps);
        //canvas.setSize(100,100);
        
        joglPane = new JPanel();
        joglPane.add(canvas);
        joglPane.requestFocusInWindow();
        joglPane.addKeyListener(this);
        joglInstance = new Jogl(this);
        canvas.addGLEventListener(joglInstance);
        
        Animator animator = new Animator(canvas);
        animator.start();
		
		
		setSize(joglPane, canvasSize);
		setSize(canvas, canvasSize);
		gbc = new GridBagConstraints();
		gbc.gridx = 1;
		gbc.gridy = 1;
		gbc.gridheight = 7;
		gbc.gridwidth = 2;
		//gbc.fill = GridBagConstraints.BOTH;
		container.add(joglPane, gbc);*/
		
		// .........................................initialize small menu panel
		gbc = new GridBagConstraints();
		gbc.gridx = 1;
		gbc.gridy = 0;
		gbc.gridwidth = 2;
        SmallMenuPane smallMenu = new SmallMenuPane(this);
        setSize(smallMenu, new Dimension(w, windowD.height - h));
        container.add(smallMenu, gbc);
        Simulation.getInstance().addObserver(this);
		
	}
	
	public JPanel getMenuPane() {
		return menuPane;
	}

	public Dimension getCanvasSize() {
		return canvasSize;
	}

	/* (non-Javadoc)
	 * @see wator.view.UI#show()
	 */
	@Override
	public void show() {
		GLProfile glp = GLProfile.getDefault();
        GLCapabilities caps = new GLCapabilities(glp);
        GLCanvas canvas = new GLCanvas(caps);
        
        joglPane = new JPanel();
        joglPane.add(canvas);
        joglPane.requestFocusInWindow();
        joglPane.addKeyListener(this);
        joglInstance = new Jogl(this);
        canvas.addGLEventListener(joglInstance);
        
        Animator animator = new Animator(canvas);
        animator.start();
				
		setSize(joglPane, canvasSize);
		setSize(canvas, canvasSize);
		GridBagConstraints gbc = new GridBagConstraints();
		gbc.gridx = 1;
		gbc.gridy = 1;
		gbc.gridheight = 7;
		gbc.gridwidth = 2;
		container.add(joglPane, gbc);
		mainFrame.setVisible(true);
		joglInstance.show();
	}
	
	public void simulate() {
		int interval = 0;
		switch (animationSpeed) { //TODO implement all speeds
		case STOP:
			SimulationThread.stopSimulation();
			interval = 0;
			break;
		case SLOW:
			interval = 1000;
			break;
		case NORMAL:
			interval = 500;
			break;
		case FAST:
			interval = 50;
			break;
		default:
			SimulationThread.stopSimulation();
			interval = 0;
			break;
		}
		if (interval != 0) {
			SimulationThread.startSimulation();
			SimulationThread.setSleepTime(interval);
		}
	}
	
	public static void setSize (Component c, Dimension d) {
		c.setSize(d);
		c.setPreferredSize(d);
		c.setMaximumSize(d);
		c.setMinimumSize(d);
	}
	
	public AnimationSpeed getAnimationSpeed() {
		return animationSpeed;
	}

	public void setAnimationSpeed(AnimationSpeed animationSpeed) {
		this.animationSpeed = animationSpeed;
	}
	
	public Grid getGrid() {
		return this.grid;
	}
	
	public void setGrid(int x, int y, int z, boolean twoDimensional, boolean visible) {
		this.grid.setSize(x, y, z);
		this.grid.setTwoDimensional(twoDimensional);
		this.grid.setVisible(visible);
	}

	@Override
	public void keyPressed(KeyEvent key) {
		switch (key.getKeyCode()) {
		case KeyEvent.VK_UP: // rot x+
			joglInstance.rotateCamera(1, 0);
			break;
		case KeyEvent.VK_DOWN: // rot x-
			joglInstance.rotateCamera(-1, 0);
			break;
		case KeyEvent.VK_LEFT: //rot y-
			joglInstance.rotateCamera(0, -1);
			break;
		case KeyEvent.VK_RIGHT: // rot y+
			joglInstance.rotateCamera(0, 1);
			break;
		case KeyEvent.VK_PLUS:
		case KeyEvent.VK_PAGE_UP:
		case KeyEvent.VK_2:
		case KeyEvent.VK_NUMPAD2: // zoom in
			joglInstance.zoomCamera(1);
			break;
		case KeyEvent.VK_MINUS:
		case KeyEvent.VK_PAGE_DOWN:
		case KeyEvent.VK_1:
		case KeyEvent.VK_NUMPAD1:	// zoom out
			joglInstance.zoomCamera(-1);
			break;
		case KeyEvent.VK_COMMA:
		//case KeyEvent.VK_NUMPAD0:
			joglInstance.resetCamPos();
			break;
		case KeyEvent.VK_ESCAPE:
			System.exit(0);
			break;
		default:
			break;
		}
		
	}

	@Override
	public void keyReleased(KeyEvent key) {
		// TODO Auto-generated method stub
		
	}
	
	@Override
	public void keyTyped(KeyEvent key) {
		keyPressed(key);
	}
	
	@Override
	public void update(Observable simulation, Object population) {
		// TODO Auto-generated method stub
		pop = Simulation.getInstance().getPopulation();
		mainFrame.setTitle(FRAME_TITLE + " (" + pop.getRound() + ". Round, "
				+ pop.countIndividuals() + " Individuals)");
	}
	
	public Population getPop() {
		return pop;
	}

	public void setPop(Population pop) {
		this.pop = pop;
	}

	private class MyDispatcher implements KeyEventDispatcher {
        @Override
        public boolean dispatchKeyEvent(KeyEvent e) {
            if (e.getID() == KeyEvent.KEY_PRESSED) {
            	keyPressed(e);
            } else if (e.getID() == KeyEvent.KEY_RELEASED) {
                keyReleased(e);
            } else if (e.getID() == KeyEvent.KEY_TYPED) {
                keyTyped(e);
            }
            return false;
        }
    }

}
